home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / ppp / dp-2.3 / sys / dp_if.c next >
Encoding:
C/C++ Source or Header  |  1992-12-13  |  59.8 KB  |  2,529 lines

  1. /*
  2.  * dp_if.c - Streams PPP top level module handles if_ and packetizing
  3.  * PPP packets.
  4.  * Copyright (C) 1990  Brad K. Clements, All Rights Reserved
  5.  */
  6. /*
  7.  * Copyright (c) 1992 Purdue University
  8.  * All rights reserved.
  9.  *
  10.  * Redistribution and use in source and binary forms are permitted
  11.  * provided that the above copyright notice and this paragraph are
  12.  * duplicated in all such forms and that any documentation,
  13.  * advertising materials, and other materials related to such
  14.  * distribution and use acknowledge that the software was developed
  15.  * by Purdue University.  The name of the University may not be used
  16.  * to endorse or promote products derived * from this software without
  17.  * specific prior written permission.
  18.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  20.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  21.  *
  22.  * Note: this copyright applies to portions of this software developed
  23.  * at Purdue beyond the software covered by the original copyright.
  24.  */
  25.  
  26. /*
  27.  * This file contains 3 basic parts, which are somewhat mixed together.
  28.  *
  29.  * "dpif" streams module
  30.  *    This can be pushed on a stream to connect it to a "dp" network
  31.  *    interface. It routes PPP packets through the stream to the user
  32.  *    process and network packets (IP) through the "dp" network interface.
  33.  * "dp" network interface
  34.  *    This is a network interface (like an ethernet driver), that implements
  35.  *    a Point to Point TCP/IP network interface.  It communicates with
  36.  *    the "dpif" streams module for input and output on the serial
  37.  *    stream and passes packets back and forth to the kernel networking
  38.  *    modules.
  39.  * "pppdial" streams device
  40.  *     This is a streams device that can be opened by a user process.
  41.  *    Messages are sent to the user process through this device when
  42.  *    the "dp" network interface needs to establish a connection to
  43.  *    send packets on a particular network interface.
  44.  */
  45. #define    VJC    1
  46. #include <sys/types.h>
  47.  
  48. #ifndef LOADABLE
  49. #include "dp.h"
  50. #endif
  51. #if NDP > 0
  52.  
  53. #define    STREAMS    1
  54.  
  55. #define    PPP_STATS    1
  56. #define PPP_SNIT    1 /* pass packets to Streams Network Interface Tap */
  57.  
  58. #define    DEBUGS    1
  59.  
  60. #include <sys/param.h>
  61. #include <sys/stream.h>
  62. #include <sys/stropts.h>
  63.  
  64. #include <sys/user.h>
  65. #include <sys/systm.h>
  66. #include <sys/mbuf.h>
  67. #include <sys/socket.h>
  68. #include <sys/errno.h>
  69. #include <sys/ioctl.h>
  70. #include <sys/file.h>
  71. #include <sys/uio.h>
  72. #include <sys/signal.h>
  73. #include <net/if.h>
  74. #include <net/netisr.h>
  75. #include <netinet/in.h>
  76. #include <netinet/in_systm.h>
  77. #include <netinet/in_var.h>
  78. #include <netinet/ip.h>
  79. #ifdef    PPP_STATS
  80. #ifdef    LOADABLE
  81. #include "slip_var.h"
  82. #else
  83. #include <sys/slip_var.h>
  84. #endif
  85. #define    INCR(comp)    ++p->pii_stats.comp
  86. #else
  87. #define    INCR(comp)
  88. #endif
  89.  
  90. #ifdef    VJC
  91. #ifdef    LOADABLE
  92. #include "slcompress.h"
  93. #else
  94. #include <sys/slcompress.h>
  95. #endif
  96. #endif
  97. #ifdef    LOADABLE
  98. #include "if_ppp.h"
  99. #include "dp_str.h"
  100. #else
  101. #include <sys/if_ppp.h>
  102. #include <sys/dp_str.h>
  103. #endif
  104. #include <netinet/tcp.h>
  105. #ifdef    DEBUGS
  106. #include <sys/syslog.h>
  107. static char *dus_str[] = {
  108.     "ACTIVE",
  109.     "ACTIVEC",
  110.     "ACTIVEU",
  111.     "WAITING",
  112.     "FAILCALL",
  113.     "DISCON",
  114.     "DOWN",
  115. };
  116. static char *cstat_str[] = {
  117.     "FAILURE",
  118.     "SUCCESS",
  119.     "IN_PROGRESS",
  120.     "NO_MODEM"
  121. };
  122. #define    DLOG(s,a)    if (dp_if_debug) log(LOG_INFO, s, a)
  123. #define    DLOG2(s,a1,a2)    if (dp_if_debug) log(LOG_INFO, s, a1, a2)
  124. #define    DLOG3(s,a,b,c)    if (dp_if_debug) log(LOG_INFO, s, a, b, c)
  125. #define    DLOG5(s,a,b,c,d,e) if (dp_if_debug) log(LOG_INFO, s, a, b, c, d, e)
  126. #define DLOGFLAGS(s)    DLOG2(s, p->pii_ifnet.if_flags, p->pii_flags)
  127. #define    DLOGSTATE(s)    if (dp_if_debug) log(LOG_INFO, s, dus_str[p->pii_dustate])
  128. int    dp_if_debug=0;
  129. int    dp_ftimo_debug=0;
  130. #define    static    
  131. #define    DLOG_ACTIVE(event)    if (dp_if_debug || dp_active_debug) log(LOG_INFO, "%c %s %d %d/%d", xmit ? 'T' : 'R', (event), act->da_nactive, act->da_misses, act->da_lookups)
  132. int dp_active_debug = 0;
  133. #else
  134. #define    DLOG(s,a)    {}
  135. #define    DLOG2(s,a1,a2)    {}
  136. #define    DLOG3(s,a,b,c)    {}
  137. #define    DLOG5(s,a,b,c,d,e) {}
  138. #define DLOGFLAGS(s)    {}
  139. #define    DLOGSTATE(s)    {}
  140. #define    DLOG_ACTIVE(s)    {}
  141. #endif
  142.  
  143. #ifdef PPP_SNIT
  144. #include <net/nit_if.h>
  145. #include <netinet/if_ether.h>
  146. /* Use a fake link level header to make etherfind and tcpdump happy. */
  147. static struct ether_header header = {{1}, {2}, ETHERTYPE_IP};
  148. static struct nit_if nif = {(caddr_t)&header, sizeof(header), 0, 0};
  149. #endif
  150.  
  151. #ifdef LOADABLE
  152. #include <sys/conf.h>
  153. #include <sys/buf.h>
  154. #include <sundev/mbvar.h>
  155. #include <sun/autoconf.h>
  156. #include <sun/vddrv.h>
  157. #endif
  158.  
  159. static    int    dp_if_open(), dp_if_close(),
  160.         dp_if_rput(), dp_if_wput(),
  161.         dp_if_wsrv(), dp_if_rsrv();
  162.  
  163. static     struct    module_info    dp_minfo ={
  164.     0xbad,"dpif",0, INFPSZ, 16384, 4096
  165. };
  166.  
  167. static    struct    qinit    dpr_init = {
  168.     dp_if_rput, dp_if_rsrv, dp_if_open, dp_if_close, NULL, &dp_minfo, NULL
  169. };
  170. static    struct    qinit    dpw_init = {
  171.     dp_if_wput, dp_if_wsrv, dp_if_open, dp_if_close, NULL, &dp_minfo, NULL
  172. };
  173. struct    streamtab    dp_ifinfo = {
  174.     &dpr_init, &dpw_init, NULL, NULL, NULL
  175. };
  176.  
  177. typedef    struct dp_if_info    PII;
  178.  
  179. PII    dupii[NDP];
  180.  
  181. static int dp_start(), dp_timer(), dp_ioctl(), dp_output();
  182. static void dp_flush();
  183.  
  184. static int dp_deftimo[PII_DP_NSTATES] = {
  185.     DP_DEF_ATIMEO,        /* Activity Timeout */
  186.     DP_DEF_CTIMEO,        /* Last TCP Close Timeout */
  187.     DP_DEF_UTIMEO,        /* Non-TCP traffic timeout */
  188.     DP_DEF_WTIMEO,        /* Call Wait Timeout */
  189.     DP_DEF_FTIMEO,        /* Failed Call Timeout */
  190.     DP_NO_TIMEOUT,        /* No Disconnect Timeout */
  191.     DP_NO_TIMEOUT        /* No Down Timeout */
  192. };
  193.  
  194. static void dp_active_init(),
  195.         dp_active_tinit(),
  196.         dp_active();
  197.  
  198. static int
  199. dp_attach(unit)
  200. int unit;
  201. {
  202.     register PII *p = &dupii[unit];
  203.     register struct ifnet *ifp = &dupii[unit].pii_ifnet;
  204.  
  205.     ifp->if_name = "dp";
  206.     ifp->if_mtu = PPP_MTU;
  207.     ifp->if_flags = IFF_POINTOPOINT;
  208.     ifp->if_unit = unit;
  209.     ifp->if_ioctl = dp_ioctl;
  210.     ifp->if_output = dp_output;
  211.     ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  212.     ifp->if_watchdog = dp_timer;
  213.     ifp->if_timer = 0;
  214.     if_attach(ifp);
  215.     p->pii_flags |= PII_FLAGS_ATTACHED;
  216. }
  217.  
  218. static void
  219. dp_init(unit)
  220. int unit;
  221. {
  222.     register PII *p = &dupii[unit];
  223.     register struct ifnet *ifp = &p->pii_ifnet;
  224.     register int i;
  225.  
  226.     /*
  227.      * Initialize the dialup stuff..
  228.      */
  229.  
  230.     if (!(ifp->if_flags & IFF_UP))
  231.     return;
  232.     if (!(p->pii_flags & PII_FLAGS_INITTED)) {
  233.     p->pii_flags |= PII_FLAGS_INITTED;
  234.     for (i = 0 ; i < PII_DP_NSTATES ; i++)
  235.         p->pii_timo[i] = dp_deftimo[i];
  236.     dp_state(p, PII_DPS_DISCON);
  237.     DLOG3("dp_init: timeouts %d %d %d\n", p->pii_timo[0] * DP_HZ,
  238.           p->pii_timo[1] * DP_HZ, p->pii_timo[2] * DP_HZ);
  239.     }
  240.  
  241.     ifp->if_flags |= IFF_UP|IFF_RUNNING;
  242. }
  243.  
  244. static int
  245. dp_if_open(q, dev, flag, sflag)
  246. queue_t    *q;
  247. dev_t    dev;
  248. int    flag,
  249.     sflag;
  250. {
  251.     if (!suser()) {
  252.     u.u_error = EPERM;
  253.     return OPENFAIL;
  254.     }
  255.     return 0;
  256. }
  257.  
  258. static int
  259. dp_if_unit(q, unit)
  260. queue_t    *q;
  261. int unit;
  262. {
  263.     register PII *p;
  264.     int    s;
  265.  
  266.     DLOG("dp_if_unit: enter %d\n", unit);
  267.     if (unit < 0 || unit >= NDP)
  268.     return EINVAL;
  269.     if (q->q_ptr)
  270.     return EBUSY;
  271.  
  272.     s = splstr();
  273.     p = &dupii[unit];
  274.  
  275.     if (p->pii_writeq) {
  276.     splx(s);
  277.     return EBUSY;
  278.     }
  279. #ifdef    VJC
  280. #ifdef    PPP_STATS
  281.     bzero(&p->pii_stats,sizeof(p->pii_stats));
  282. #endif
  283.     sl_compress_init(&p->pii_sc_comp);
  284. #endif
  285.     dp_active_init(&p->pii_active);
  286.     if (!(p->pii_flags & PII_FLAGS_ATTACHED))
  287.     dp_attach(unit); /* attach it */
  288.     p->pii_writeq = q;
  289.     RD(q)->q_ptr = q->q_ptr = (caddr_t) p;    /* set write Q and read Q to point here */
  290.     p->pii_flags |= PII_FLAGS_INUSE|PII_FLAGS_ATTACHED;
  291.     DLOG("dp_if_unit: exit %d\n", unit);
  292.     splx(s);
  293.     return 0;
  294. }
  295.  
  296. static int
  297. dp_if_close(q)
  298.     queue_t    *q;            /* queue info */
  299. {
  300.     PII    *p = (PII *) q->q_ptr;
  301.     int    s;
  302.  
  303.     s = splimp();
  304.     dp_flush(p, q);
  305.     if (p) {
  306.     p->pii_flags &= ~PII_FLAGS_INUSE;
  307.     switch (p->pii_dustate) {
  308.      case PII_DPS_DOWN:
  309.         break;
  310.      case PII_DPS_DISCON:
  311.      case PII_DPS_WAITING:
  312.      case PII_DPS_ACTIVE:
  313.      case PII_DPS_FAILCALL:
  314.         dp_state(p, PII_DPS_DISCON);
  315.         break;
  316.      default:
  317.         DLOG("dp_if_close: unknown state %d\n", p->pii_dustate);
  318.         break;
  319.     }
  320.     p->pii_writeq = (queue_t *)0;
  321.     q->q_ptr = (char *)0;
  322.     DLOG("dp_if%d: closed\n", (p-dupii)/sizeof(PII));
  323.     }
  324.     else
  325.     DLOG("dp_if: closed\n", p);
  326.     splx(s);
  327.     return(0);            /* no work to be done */
  328. }
  329.  
  330. static void
  331. dp_flush(p, q)
  332. register PII *p;
  333. register queue_t *q;
  334. {
  335.     if (p)
  336.     if_qflush(&p->pii_ifnet.if_snd);
  337.     if (q) {
  338.     flushq(q, FLUSHALL);
  339.     flushq(OTHERQ(q), FLUSHALL);
  340.     }
  341. }
  342.  
  343.  
  344. static int
  345. dp_ioc_sint(mp, i, valp)
  346. register mblk_t *mp;
  347. register struct iocblk *i;
  348. int *valp;
  349. {
  350.     if (i->ioc_count != sizeof(int)) {
  351.     i->ioc_error = EINVAL;
  352.     return -1;
  353.     }
  354.     *valp = *(int *)mp->b_cont->b_rptr;
  355.     return 0;
  356. }
  357.  
  358. /*
  359.  *
  360.  * dp_callstat() provides for the following state transitions..
  361.  *
  362.  * State    Status         New State
  363.  * FAILCALL    IN_PROGRESS    WAITING        (dplogin starting..)
  364.  * DISCON    IN_PROGRESS    WAITING        (dplogin starting..)
  365.  * WAITING    FAILURE        FAILCALL    (couldn't complete call)
  366.  * WAITING    NO_MODEM    DISCON        (no modems, immediate retry ok)
  367.  * WAITING    SUCCESS        ACTIVE        (start packets flowing)
  368.  */
  369.     
  370. static int
  371. dp_callstat(p, stat)
  372. register PII *p;
  373. char stat;
  374. {
  375. #ifdef    DEBUGS
  376.     if (dp_if_debug) {
  377.     if (DP_VALID_STATUS(stat))
  378.         log(LOG_INFO, "dp_callstat: state %s stat %s\n",
  379.         dus_str[p->pii_dustate], cstat_str[stat]);
  380.     else
  381.         log(LOG_INFO, "dp_callstat: state %s stat %d\n",
  382.         dus_str[p->pii_dustate], stat);
  383.     }
  384. #endif
  385.     switch (p->pii_dustate) {
  386.      case PII_DPS_DOWN:
  387.      case PII_DPS_ACTIVE:
  388.     break;
  389.  
  390.      /*
  391.       * Not connected, so transition to WAITING if dplogin is starting up..
  392.       */
  393.      case PII_DPS_FAILCALL:
  394.      case PII_DPS_DISCON:
  395.     switch (stat) {
  396.      case DP_IN_PROGRESS:
  397.         dp_state(p, PII_DPS_WAITING);
  398.         break;
  399.      case DP_SUCCESS:
  400.         dp_state(p, PII_DPS_ACTIVE);
  401.         break;
  402.     }
  403.  
  404.      /*
  405.       * Waiting for a connection to be established.
  406.       * Respond properly to the result returned.
  407.       */
  408.      case PII_DPS_WAITING:
  409.     switch (stat) {
  410.      case DP_SUCCESS:
  411.         dp_state(p, PII_DPS_ACTIVE);
  412.         (void)dp_start(p);
  413.         break;
  414.      case DP_FAILURE:
  415.         dp_state(p, PII_DPS_FAILCALL);
  416.         dp_flush(p, p->pii_writeq);
  417.         break;
  418.      case DP_NO_MODEM:
  419.         dp_state(p, PII_DPS_DISCON);
  420.         dp_flush(p, p->pii_writeq);
  421.     }
  422.     break;
  423.     }
  424. }
  425.  
  426. static int
  427. dp_if_wput(q, mp)
  428. queue_t  *q;
  429. register mblk_t *mp;
  430. {
  431.  
  432.     register struct iocblk *i;
  433.     register PII *p;
  434.     int x;
  435.  
  436.     switch (mp->b_datap->db_type) {
  437.      case  M_FLUSH:
  438.     if (*mp->b_rptr & FLUSHW)
  439.         flushq(q, FLUSHDATA);
  440.     putnext(q, mp);        /* send it along too */
  441.     break;
  442.  
  443.      case M_DATA:
  444.     if (!q->q_ptr) {
  445.         mp->b_datap->db_type = M_ERROR;
  446.         mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
  447.         *mp->b_wptr++ = ENXIO;
  448.         qreply(q, mp);
  449.     }
  450.     else
  451.         putq(q, mp);    /* queue it for my service routine */
  452.     break;
  453.  
  454.      case M_IOCTL:
  455.     i = (struct iocblk *) mp->b_rptr;
  456.     p = (PII *) q->q_ptr;
  457.     if (!p && i->ioc_cmd != SIOCSIFUNIT)
  458.         goto passalong;
  459.  
  460.     switch (i->ioc_cmd) {
  461.      case SIOCSIFCOMPAC:    /* enable or disable AC compression */
  462.         if (i->ioc_count != sizeof(u_char)) 
  463.         goto passalong;
  464.         DLOG("dp_if: SIFCOMPAC %d\n",  *(u_char *) mp->b_cont->b_rptr);
  465.         if ( *(u_char *) mp->b_cont->b_rptr) 
  466.         p->pii_flags |= PII_FLAGS_COMPAC;
  467.         else
  468.         p->pii_flags &= ~PII_FLAGS_COMPAC;
  469.         goto passalong;
  470.     
  471.      case SIOCSIFCOMPPROT:    /* enable or disable PROT  compression */
  472.         DLOG("dp_if: SIFCOMPPROT %d\n",  *(u_char *) mp->b_cont->b_rptr);
  473.         if (i->ioc_count != sizeof(u_char))
  474.         goto passalong;
  475.         if ( *(u_char *) mp->b_cont->b_rptr) 
  476.         p->pii_flags |= PII_FLAGS_COMPPROT;
  477.         else
  478.         p->pii_flags &= ~PII_FLAGS_COMPPROT;
  479.         goto passalong;
  480.  
  481.      case SIOCSIFVJCOMP:    /* enable or disable VJ compression */
  482. #ifdef    VJC
  483.         if (i->ioc_count != sizeof(u_char)) 
  484.         goto passalong;
  485.         DLOG("dp_if: SIFVJCOMP %d\n",  *(u_char *) mp->b_cont->b_rptr);
  486.         if ( *(u_char *) mp->b_cont->b_rptr) 
  487.         p->pii_flags |= PII_FLAGS_VJC_ON;
  488.         else
  489.         p->pii_flags &= ~PII_FLAGS_VJC_ON;
  490.         mp->b_datap->db_type = M_IOCACK;
  491. #else
  492.         mp->b_datap->db_type = M_IOCNAK;
  493.         i->ioc_error = EINVAL;
  494.         i->ioc_count = 0;
  495. #endif
  496.         qreply(q, mp);
  497.         break;
  498.  
  499.     /*
  500.      * The remaining ioctl's support the options for dialup.
  501.      */
  502.      case SIOCSIFUNIT:
  503.         DLOG2("dp_if: SIFSIFUNIT %d p %x\n",
  504.           *(int *)mp->b_cont->b_rptr, p);
  505.         if (i->ioc_count != sizeof(int)) {
  506.         i->ioc_error = EINVAL;
  507.         goto iocnak;
  508.         }
  509.         if (x = dp_if_unit(q, *(int *)mp->b_cont->b_rptr)) {
  510.         i->ioc_error = x;
  511.         goto iocnak;
  512.         }
  513.         else {
  514.         p = (PII *) q->q_ptr;
  515.         goto iocack;
  516.         }
  517.  
  518.      case SIOCGIFUNIT:    /* get unit number */
  519.      case SIOCGETU:    
  520.         DLOG("dp_if: SIFGIFUNIT %d\n", p->pii_ifnet.if_unit);
  521.         if (mp->b_cont = allocb(sizeof(int), BPRI_MED)) {
  522.         *(int *)mp->b_cont->b_wptr = p->pii_ifnet.if_unit;
  523.         mp->b_cont->b_wptr += i->ioc_count  = sizeof(int);
  524.         mp->b_datap->db_type = M_IOCACK;
  525.         }
  526.         else {
  527.         i->ioc_error = ENOSR;
  528.         i->ioc_count = 0;
  529.         mp->b_datap->db_type = M_IOCNAK;
  530.         }
  531.         qreply(q, mp);
  532.         break;
  533.  
  534.      case SIOCCALLSTAT:    /* Report Call Status */
  535.         DLOG("dp_if: SIFCALLSTAT %d\n", *(char *)mp->b_cont->b_rptr);
  536.         if (i->ioc_count != sizeof(char)) {
  537.         i->ioc_error = EINVAL;
  538. iocnak:
  539.         i->ioc_count = 0;
  540.         mp->b_datap->db_type = M_IOCNAK;
  541.         qreply(q, mp);
  542.         break;
  543.         }
  544.         x = splimp();
  545.         dp_callstat(p, (int)*mp->b_cont->b_rptr);
  546.         splx(x);
  547. iocack:
  548.         mp->b_datap->db_type = M_IOCACK;
  549.         qreply(q, mp);
  550.         break;
  551.  
  552.      case SIOCSDPTIMEO:    /* Set Timeouts */
  553.         if (i->ioc_count != DP_NTIMEOUTS * sizeof(u_long) * DP_NTIMEOUTS) {
  554.         i->ioc_error = EINVAL;
  555.         goto iocnak;
  556.         }
  557.         dp_settimos(p, (u_long *)mp->b_cont->b_rptr, 0, DP_NTIMEOUTS);
  558.         break;
  559.      case SIOCGDPTIMEO:    /* Get Timeouts */
  560.         if (mp->b_cont = allocb(DP_NTIMEOUTS * sizeof(u_long), BPRI_MED)) {
  561.         dp_gettimos(p, (u_long *)mp->b_cont->b_wptr, 0, DP_NTIMEOUTS);
  562.         mp->b_cont->b_wptr += i->ioc_count
  563.                     = DP_NTIMEOUTS * sizeof(u_long);
  564.         mp->b_datap->db_type = M_IOCACK;
  565.         }
  566.         else {
  567.         i->ioc_error = ENOSR;
  568.         i->ioc_count = 0;
  569.         mp->b_datap->db_type = M_IOCNAK;
  570.         }
  571.         qreply(q, mp);
  572.         break;
  573.  
  574.      default:        /* unknown IOCTL call */
  575. passalong:
  576.         putnext(q,mp);    /* pass it along */
  577.     }
  578.     DLOG("dp_if_wput: Pii->flags %x\n", p->pii_flags);
  579.     break;    
  580.      default:
  581.     putnext(q,mp);    /* don't know what to do with this, so send it along*/
  582.     }
  583. }
  584.  
  585. static int
  586. dp_if_wsrv(q)
  587. queue_t    *q;
  588. {
  589.     register mblk_t *mp;
  590.     register PII *p;
  591.  
  592.     p = (PII *) q->q_ptr;
  593.  
  594.     while ((mp = getq(q)) != NULL) {
  595.     /*
  596.      * We can only get M_DATA types into our Queue,
  597.      * due to our Put function
  598.      */
  599.     if (!canput(q->q_next)) {
  600.         putbq(q, mp);
  601.         return;
  602.     }
  603.     putnext(q, mp);    /* just pass it along, nothing to do in this direction */
  604.     }
  605. }
  606.  
  607. static int
  608. dp_if_rput(q, mp)
  609. queue_t *q;
  610. register mblk_t *mp;
  611. {
  612.     register u_char *c;
  613.     register PII *p;
  614.  
  615.     switch (mp->b_datap->db_type) {
  616.      case M_FLUSH:
  617.     if (*mp->b_rptr & FLUSHR)
  618.         flushq(q, FLUSHDATA);
  619.     putnext(q, mp);        /* send it along too */
  620.     break;
  621.  
  622.      case M_DATA:
  623.     putq(q, mp);    /* queue it for my service routine */
  624.     break;
  625.  
  626.      case M_CTL:        /* could be a message from below */
  627.     p = (PII *) q->q_ptr;
  628.     c = (u_char *) mp->b_rptr;
  629.     switch (*c) {
  630.      case IF_INPUT_ERROR:
  631.         p->pii_ifnet.if_ierrors++;
  632.         INCR(sl_ierrors);
  633.         DLOG("dp_if: input error inc to %d\n", p->pii_ifnet.if_ierrors);
  634.         break;
  635.      case IF_OUTPUT_ERROR:
  636.         p->pii_ifnet.if_oerrors++;
  637.         INCR(sl_oerrors);
  638.         DLOG("dp_if: output error inc to %d\n", p->pii_ifnet.if_oerrors);
  639.         break;
  640.      default:
  641.         break;
  642.     }
  643.     freemsg(mp);
  644.     /* putnext(q, mp); */
  645.     break;
  646.      default:
  647.     putnext(q,mp);    /* don't know what to do with this, so send it along*/
  648.     }
  649. }
  650.  
  651. static int
  652. dp_if_rsrv(q)
  653. queue_t    *q;
  654. {
  655.     register mblk_t *mp, *m0;
  656. #ifdef    VJC
  657.     register mblk_t *mvjc;
  658.     unsigned char *cp;
  659.  
  660. #endif
  661.     register PII    *p;
  662.     struct ifnet    **ifp;
  663.     struct ppp_header    *ph;
  664.     struct mbuf    *mb1, *mb2,*mbtail;
  665.     int    len,xlen,count,s;
  666.     u_char    *rptr;
  667.  
  668.     p = (PII *) q->q_ptr;
  669.  
  670.     while ((mp = getq(q)) != NULL) {
  671.     /* we can only get M_DATA types into our Queue, due to our Put function */
  672.     m0 = mp;    /* remember first message block */
  673.     ph = (struct ppp_header *) mp->b_rptr;
  674.     /* assume ppp_header is completely in first block */
  675.     if (mp->b_wptr - mp->b_rptr < sizeof(struct ppp_header)) {
  676.         freemsg(mp);
  677.         p->pii_ifnet.if_ierrors++;
  678.         continue;
  679.     }
  680. #ifdef    VJC
  681.     switch (ntohs(ph->ph_protocol)) {
  682.      case PPP_IP:
  683.         break;
  684.      case PPP_VJC_COMP:
  685.         if (p->pii_flags & PII_FLAGS_VJC_ON) {
  686.         for (xlen=0, mvjc = mp ; mvjc ; mvjc = mvjc->b_cont)
  687.             xlen += (mvjc->b_wptr - mvjc->b_rptr);
  688.         xlen -= sizeof(struct ppp_header);
  689.         if (!(mvjc = allocb(128, BPRI_MED))) {
  690.             /* get a 128 byte buffer for IP header*/
  691.             putbq(q,mp);
  692.             qenable(q);
  693.             return;
  694.         }
  695.         mvjc->b_wptr += 128;
  696.         linkb(mvjc,mp);
  697.         if (!pullupmsg(mvjc,-1)) {
  698.             /* string em all together. ugh what a waste */
  699.             freemsg(mvjc);
  700.             continue;
  701.         }
  702.         cp = mvjc->b_rptr + 128 + sizeof(struct ppp_header);
  703.         m0 = mp = mvjc;
  704.         xlen = sl_uncompress_tcp(&cp,xlen, TYPE_COMPRESSED_TCP, &p->pii_sc_comp);
  705.         if (!xlen) {
  706.             DLOG("dp: sl_uncompress failed on type Compressed",0);
  707.             goto reject;
  708.         }
  709.         mp->b_rptr = cp - sizeof(struct ppp_header);
  710.         ((struct ppp_header *) mp->b_rptr)->ph_protocol = htons(PPP_IP);
  711.         break;
  712.         }
  713.             
  714.      case PPP_VJC_UNCOMP:
  715.         if (p->pii_flags & PII_FLAGS_VJC_ON) {
  716.         cp = (unsigned char *) mp->b_rptr + sizeof(struct ppp_header);
  717.         if (sl_uncompress_tcp(&cp, 1, TYPE_UNCOMPRESSED_TCP, &p->pii_sc_comp)) {
  718.             ((struct ppp_header *) mp->b_rptr)->ph_protocol = htons(PPP_IP);
  719.             break;
  720.         }
  721.         DLOG("dp: sl_uncompress failed on type Uncompresed\n",0);
  722. reject:
  723.         freemsg(mp);
  724.         continue;                
  725.         }
  726.      default:
  727. #endif
  728. #ifndef    VJC
  729.         if (ntohs(ph->ph_protocol) != PPP_IP) {
  730. #endif
  731. #ifdef    DEBUGS
  732.         if (dp_if_debug) {
  733.             switch (ntohs(ph->ph_protocol) & 0xf000) {
  734.              case PPP_LCP:
  735.             DLOG("dp: LCP packet 0x%x\n", ntohs(ph->ph_protocol));
  736.             break;
  737.              case PPP_NCP:
  738.             DLOG("dp: NCP packet 0x%x\n", ntohs(ph->ph_protocol));
  739.             break;
  740.              default:
  741.             DLOG("dp: unknown protocol 0x%x\n",
  742.                  ntohs(ph->ph_protocol));
  743.             }
  744.         }
  745. #endif
  746.         INCR(sl_ipackets);
  747.         if (!canput(q->q_next)) {
  748.             putbq(q, mp);
  749.             return;
  750.         }
  751.         putnext(q,mp);
  752.         p->pii_ifnet.if_ipackets++;
  753.         continue;
  754. #ifndef    VJC
  755.         }
  756. #endif
  757.     }
  758.     len  = 0;
  759.     mb1 = NULL;
  760.     xlen = mp->b_wptr - (rptr = mp->b_rptr);
  761.     while (mp) {
  762.         if (len < 1) {
  763.         MGET(mb2, M_DONTWAIT, MT_DATA);
  764.         if (!mb2) {
  765.             p->pii_ifnet.if_ierrors++;
  766.             putbq(q,m0);
  767.             qenable(q);
  768.             if (mb1)
  769.             m_freem(mb1);    /* discard what we've used already */
  770.             return;
  771.             }            /* if we couldn't get a buffer, put back the message and try later */
  772.             len = MLEN;
  773.             mb2->m_len = 0;
  774.             if (mb1) {
  775.             mbtail->m_next = mb2;
  776.             mbtail = mb2;
  777.             }
  778.             else 
  779.             mbtail = mb1 = mb2;
  780.         }
  781.         count = MIN(xlen, len);
  782.         bcopy((char *) rptr, mtod(mb2, char *) + mb2->m_len, count);
  783. #ifdef    PPP_STATS
  784.         p->pii_stats.sl_ibytes += count;
  785. #endif
  786.         rptr += count;
  787.         len -= count;
  788.         xlen -= count;
  789.         mb2->m_len += count;
  790.         if (!xlen) {    /* move to the next mblk */
  791.         mp = mp->b_cont;
  792.         if (mp)
  793.             xlen = mp->b_wptr - (rptr = mp->b_rptr);
  794.         }
  795.     }
  796. #define    HADJ    (sizeof(struct ppp_header) - sizeof(struct ifnet *))
  797.         /* note, HADJ >= 0 is assumed */
  798.  
  799.     ifp = (struct ifnet **) (mtod(mb1, u_char *) + HADJ);
  800.     *ifp =  &p->pii_ifnet;    /* stick ifnet * in front of packet */
  801.     mb1->m_off += HADJ;
  802.     mb1->m_len -= HADJ;
  803.     freemsg(m0);
  804. #ifdef PPP_SNIT
  805.     if (p->pii_ifnet.if_flags & IFF_PROMISC) {
  806.         struct mbuf *m = mb1;
  807.  
  808.         len = 0;
  809.         do {
  810.         len += m->m_len;
  811.         } while (m = m->m_next);
  812.         nif.nif_bodylen = len - sizeof(struct ifnet *);
  813.         mb1->m_off += sizeof(struct ifnet *);
  814.         snit_intr(&p->pii_ifnet, mb1, &nif);
  815.         mb1->m_off -= sizeof(struct ifnet *);
  816.     }
  817. #endif
  818.     p->pii_ifnet.if_ipackets++;
  819.     INCR(sl_ipackets);
  820. #define    IPADJ    sizeof(struct ppp_header)
  821.     dp_active(p, (struct ip *)(mtod(mb1, u_char *) + IPADJ),
  822.           mb1->m_len - IPADJ, 0);
  823.     s = splimp();
  824.     if (IF_QFULL(&ipintrq)) {
  825.         IF_DROP(&ipintrq);
  826.         p->pii_ifnet.if_ierrors++;
  827.         m_freem(mb1);
  828.     }
  829.     else {
  830.         IF_ENQUEUE(&ipintrq, mb1);
  831.         schednetisr(NETISR_IP);
  832.     }
  833.     splx(s);
  834.     }    /* end while */
  835.  
  836. }
  837.  
  838. /* ifp output procedure */
  839. int
  840. dp_output(ifp, m0, dst)
  841.     struct ifnet *ifp;
  842.     struct mbuf *m0;
  843.     struct sockaddr *dst;
  844. {
  845.     register PII    *p = &dupii[ifp->if_unit];
  846.     struct mbuf    *m;
  847.     int    error, s;
  848.     u_short protocol;
  849.     
  850.     DLOG2("dp_output: state %s flags %x\n", dus_str[p->pii_dustate], p->pii_flags);
  851.  
  852.     error = 0;
  853.     if (!(ifp->if_flags & IFF_RUNNING)) {
  854.     error = ENETDOWN;
  855.     goto getout;
  856.     }
  857.  
  858.     switch (p->pii_dustate) {
  859.      case PII_DPS_ACTIVE:
  860.     /*
  861.      * The easy case..
  862.      * The line is active and we are set..
  863.      */
  864.     break;
  865.  
  866.      case PII_DPS_DOWN:
  867.      case PII_DPS_FAILCALL:
  868.     /*
  869.      * If the net is marked down or we have recently failed in calling,
  870.      * might as well give up now.
  871.      */
  872.     DLOGSTATE("dp_output: NETDOWN %s\n");
  873.     error = ENETDOWN;
  874.     goto getout;
  875.  
  876.      case PII_DPS_WAITING:
  877.     /*
  878.      * If we are waiting on a call to go through, queue this packet
  879.      * and don't signal any error. 
  880.      */
  881.     DLOGFLAGS("dp_output: DPS_WAITING %x %x\n");
  882.     goto qpacket;
  883.  
  884.      case PII_DPS_DISCON:
  885.     /*
  886.      * If not already talking on the line,
  887.      * try to initiate a call.
  888.      */
  889.     switch (dst->sa_family) {
  890. #ifdef    INET
  891.      case AF_INET:
  892.         if (duipreq(m0, dst, ifp)) {
  893.         DLOGFLAGS("dp_output: duipreq failed %x %x\n");
  894.         error = ENETDOWN;
  895.         goto getout;
  896.         }
  897.         break;
  898. #endif
  899.      default:
  900.         /*
  901.          * Punt for now.
  902.          */
  903.         DLOGFLAGS("dp_output: DISCON bad family %x %x\n");
  904.         error = ENETDOWN;
  905.         goto getout;
  906.     }
  907.     dp_state(p, PII_DPS_WAITING);
  908.     DLOGFLAGS("dp_output: duipreq in progress %x %x\n");
  909.     goto qpacket;
  910.  
  911.      default:
  912.     DLOG("dp_output: unknown state %d\n", p->pii_dustate);
  913.     break;
  914.     }
  915.  
  916. qpacket:
  917.     switch (dst->sa_family) {
  918. #ifdef    INET
  919.      case AF_INET:
  920. #ifdef PPP_SNIT
  921.     if (ifp->if_flags & IFF_PROMISC) {
  922.         struct mbuf *m = m0;
  923.         int len = 0;
  924.         do {
  925.         len += m->m_len;
  926.         } while (m = m->m_next);
  927.         nif.nif_bodylen = len;
  928.         snit_intr(ifp, m0, &nif);
  929.     }
  930. #endif
  931.     protocol = PPP_IP;
  932.     break;
  933. #endif
  934. #ifdef    NS
  935.      case AF_NS:
  936.     protocol = PPP_XNS;
  937.     break;
  938. #endif
  939.      default:
  940.     printf("dp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
  941.     error = EAFNOSUPPORT;
  942.     goto getout;
  943.     }
  944.     /*
  945.      * Prepend the protocol to this packet.
  946.      */
  947.     if (m0->m_off > MMAXOFF || MMINOFF + sizeof(protocol) > m0->m_off) {
  948.     m = m_get(M_DONTWAIT, MT_HEADER);
  949.     if (m == 0) {
  950.         error = ENOBUFS;
  951.         goto getout;
  952.     }
  953.     m->m_next = m0;
  954.     m->m_len = sizeof(protocol);
  955.     m0 = m;
  956.     }
  957.     else {
  958.     m0->m_off -= sizeof(protocol);
  959.     m0->m_len += sizeof(protocol);
  960.     }
  961.     bcopy((caddr_t)&protocol, mtod(m0, caddr_t), sizeof(protocol));
  962.  
  963.     s = splimp();
  964.     if (IF_QFULL(&ifp->if_snd))
  965.     IF_DROP(&ifp->if_snd);
  966.     IF_ENQUEUE(&ifp->if_snd, m0);
  967.     error = dp_start(p);
  968.     splx(s);
  969.     if (error) {
  970.     INCR(sl_oerrors);
  971.     p->pii_ifnet.if_oerrors++;
  972.     }
  973.     return(error);        /* gads, streams are great */
  974. getout:
  975.     if (m0)
  976.     m_freem(m0);
  977.     if (error) {
  978.     INCR(sl_oerrors);
  979.     p->pii_ifnet.if_oerrors++;
  980.     }
  981.     return(error);        /* gads, streams are great */
  982. }
  983.  
  984. static int
  985. dp_start(p)
  986.     register PII    *p;
  987. {
  988.     struct mbuf    *m0, *m1;
  989.     int len;
  990.     u_short    protocol;
  991.     mblk_t    *mp;
  992.     int s;
  993. #ifdef    VJC
  994.     u_char    type;
  995. #endif
  996.  
  997.     while (p->pii_ifnet.if_snd.ifq_head && p->pii_writeq &&
  998.        (p->pii_dustate == PII_DPS_ACTIVE)) {
  999.     IF_DEQUEUE(&p->pii_ifnet.if_snd, m0);
  1000.     protocol = *mtod(m0, u_short *);
  1001.     bcopy(mtod(m0, caddr_t), (caddr_t)&protocol, sizeof(protocol));
  1002.     m0->m_off += sizeof(protocol);
  1003.     m0->m_len -= sizeof(protocol);
  1004.     if (m0->m_len == 0)
  1005.         m0 = m_free(m0);
  1006. #ifdef    VJC
  1007.     if ((protocol == PPP_IP) && (p->pii_flags & PII_FLAGS_VJC_ON)) {
  1008.         register struct ip *ip;
  1009.         if ((m0->m_off > MMAXOFF || m0->m_len < sizeof(struct ip)) &&
  1010.         (m0 = m_pullup(m0, sizeof(struct ip))) == 0) {
  1011.         INCR(sl_oerrors);
  1012.         p->pii_ifnet.if_oerrors++;
  1013.         return ENOBUFS;
  1014.         }
  1015.  
  1016.         ip = mtod(m0, struct ip *);
  1017.         dp_active(p, ip, m0->m_len, 1);
  1018.         if (ip->ip_p == IPPROTO_TCP) {
  1019.         type = sl_compress_tcp(m0, ip, &p->pii_sc_comp, 1);
  1020.         switch (type) {
  1021.          case TYPE_UNCOMPRESSED_TCP:
  1022.             protocol = PPP_VJC_UNCOMP;
  1023.             break;
  1024.          case TYPE_COMPRESSED_TCP:
  1025.             protocol = PPP_VJC_COMP;
  1026.             break;    
  1027.         }
  1028.         }
  1029.     }
  1030. #endif
  1031.     len = 0;
  1032.     for (m1 = m0; m1; m1 = m1->m_next) 
  1033.         len += m1->m_len;
  1034.     if (!(p->pii_flags & PII_FLAGS_COMPAC))
  1035.         len += 2;    /* if we are not compac, then need 2 extra bytes */
  1036.     if (!(p->pii_flags & PII_FLAGS_COMPPROT))
  1037.         len++;
  1038.     len++;
  1039.     /*
  1040.      * We never need to check the actual protocol,  since
  1041.      * its always either PPP_IP, PPP_VJC_*, or PPP_XNS
  1042.      */
  1043.     if (!(mp = allocb(len, BPRI_LO))) {
  1044.         INCR(sl_oerrors);
  1045.         p->pii_ifnet.if_oerrors++;
  1046.         m_freem(m0);
  1047.         return ENOBUFS;
  1048.     }
  1049. #ifdef    PPP_STATS
  1050.     p->pii_stats.sl_obytes += len;
  1051. #endif
  1052.     if (!(p->pii_flags & PII_FLAGS_COMPAC)) {
  1053.         *mp->b_wptr++ = PPP_ALLSTATIONS;
  1054.         *mp->b_wptr++ = PPP_UI;
  1055.     }
  1056.     if (!(p->pii_flags & PII_FLAGS_COMPPROT))
  1057.         *mp->b_wptr++ = 0;
  1058.     *mp->b_wptr++ = protocol & 0xff;
  1059.     for (m1 = m0; m1; m1 = m1->m_next) {        /* copy all data */
  1060.         bcopy(mtod(m1, char *), (char *) mp->b_wptr, m1->m_len);
  1061.         mp->b_wptr += m1->m_len;
  1062.     }
  1063.     m_freem(m0);
  1064.  
  1065.     s = splstr();
  1066.     putq(p->pii_writeq, mp);
  1067.     splx(s);
  1068.  
  1069.     p->pii_ifnet.if_opackets++;
  1070.     INCR(sl_opackets);
  1071.     }
  1072.     return 0;
  1073. }
  1074.  
  1075. /*
  1076.  * if_ ioctl requests 
  1077. */
  1078. dp_ioctl(ifp, cmd, data)
  1079. register struct ifnet *ifp;
  1080. int    cmd;
  1081. caddr_t    data;
  1082. {
  1083.     register struct ifaddr *ifa = (struct ifaddr *) data;
  1084.     register struct ifreq *ifr = (struct ifreq *) data;
  1085.     int    s = splimp(), error = 0;
  1086.  
  1087.     if (ifa == NULL ) {
  1088.     splx(s);
  1089.     return(EFAULT);
  1090.     }
  1091.  
  1092.     switch (cmd) {
  1093.      case SIOCSIFFLAGS:
  1094.     if (!suser()) {
  1095.         error = EPERM;
  1096.         break;
  1097.     }
  1098.     ifp->if_flags &= (IFF_CANTCHANGE);    /* clear the flags that can be cleared */
  1099.     ifp->if_flags |= (ifr->ifr_flags & ~IFF_CANTCHANGE); /* or in the flags that can
  1100.                                 be changed */
  1101.     dp_init(ifp->if_unit);
  1102.     break;
  1103.      case SIOCGIFFLAGS:
  1104.     ifr->ifr_flags = ifp->if_flags;
  1105.     break;
  1106.      case SIOCSIFADDR:
  1107.     if (ifa->ifa_addr.sa_family != AF_INET) 
  1108.         error = EAFNOSUPPORT;
  1109.     break;
  1110.      case SIOCSIFDSTADDR:
  1111.     if (ifa->ifa_addr.sa_family != AF_INET)
  1112.         error = EAFNOSUPPORT;
  1113.     break;
  1114.  
  1115. #ifndef    ifr_mtu
  1116. #define    ifr_mtu    ifr_metric
  1117. #endif
  1118.      case SIOCSIFMTU:
  1119.     if (!suser()) {
  1120.         error = EPERM;
  1121.         break;
  1122.     }
  1123.     if (ifr->ifr_mtu >
  1124.         (4096 - (sizeof(struct ppp_header) + sizeof(u_short)))) {
  1125.         error = EINVAL;
  1126.         break;
  1127.     }
  1128.     ifp->if_mtu = ifr->ifr_mtu;
  1129.     break;
  1130.      case SIOCGIFMTU:
  1131.     ifr->ifr_mtu = ifp->if_mtu;
  1132.     break;
  1133.  
  1134.      case SIOCICALLSTAT:
  1135.     dp_callstat(&dupii[ifp->if_unit], ifr->ifr_data[0]);
  1136.     break;
  1137.  
  1138.      case SIOCSDPIATIMEO:    /* Set Activity Timeouts */
  1139.     dp_settimos(&dupii[ifp->if_unit], (u_long *)ifr->ifr_data,
  1140.             DP_ATIMEOUTS, DP_NATIMEOUTS);
  1141.     break;
  1142.      case SIOCGDPIATIMEO:    /* Get Activity Timeouts */
  1143.     dp_gettimos(&dupii[ifp->if_unit], (u_long *)ifr->ifr_data,
  1144.             DP_ATIMEOUTS, DP_NATIMEOUTS);
  1145.     break;
  1146.  
  1147.      case SIOCSDPICTIMEO:    /* Set Call Timeouts */
  1148.     dp_settimos(&dupii[ifp->if_unit], (u_long *)ifr->ifr_data,
  1149.             DP_CTIMEOUTS, DP_NCTIMEOUTS);
  1150.     break;
  1151.      case SIOCGDPICTIMEO:    /* Get Call Timeouts */
  1152.     dp_gettimos(&dupii[ifp->if_unit], (u_long *)ifr->ifr_data,
  1153.             DP_CTIMEOUTS, DP_NCTIMEOUTS);
  1154.     break;
  1155.  
  1156.      case SIOCGDPIISTATS:    /* Get Input Stats */
  1157.     dp_gstats(&dupii[ifp->if_unit], (u_int *)ifr->ifr_data, 0);
  1158.     break;
  1159.  
  1160.      case SIOCGDPIOSTATS:    /* Get Output Stats */
  1161.     dp_gstats(&dupii[ifp->if_unit], (u_int *)ifr->ifr_data, 1);
  1162.     break;
  1163.  
  1164.      default:
  1165.     error = EINVAL;
  1166.     break;
  1167.     }
  1168.     splx(s);
  1169.     return(error);
  1170. }
  1171.  
  1172. static
  1173. dp_gstats(p, stats, out)
  1174. register PII *p;
  1175. register u_int *stats;
  1176. int out;
  1177. {
  1178. #ifdef    PPP_STATS
  1179.     struct slipstat *ss = &p->pii_stats;
  1180.     if (out) {
  1181.     stats[0] = ss->sl_obytes;
  1182.     stats[1] = ss->sl_opackets;
  1183.     stats[2] = ss->sl_oerrors;
  1184.     }
  1185.     else {
  1186.     stats[0] = ss->sl_ibytes;
  1187.     stats[1] = ss->sl_ipackets;
  1188.     stats[2] = ss->sl_ierrors;
  1189.     }
  1190. #endif    PPP_STATS
  1191. }
  1192.  
  1193. static
  1194. dp_settimos(p, to, t0, nt)
  1195. register PII *p;
  1196. register u_long *to;
  1197. register int t0, nt;
  1198. {
  1199.     register int t;
  1200.     for (t = 0 ; t < nt ; t++)
  1201.     switch (to[t]) {
  1202.      case DP_DEF_TIMEOUT:
  1203.         break;
  1204.      case DP_NO_TIMEOUT:
  1205.         p->pii_timo[t0 + t] = DP_NO_TIMEOUT;
  1206.         break;
  1207.      default:
  1208.         p->pii_timo[t0 + t] = to[t] / DP_HZ;
  1209.         break;
  1210.     }
  1211.     /*
  1212.      * If we are using certain timeouts, do extra processing
  1213.      * on each packet.
  1214.      */
  1215.     if (p->pii_timo[DP_CTIMEO] == DP_NO_TIMEOUT &&
  1216.     p->pii_timo[DP_UTIMEO] == DP_NO_TIMEOUT)
  1217.     p->pii_flags &= ~PII_FLAGS_ACTIVE;
  1218.     else
  1219.     p->pii_flags |=  PII_FLAGS_ACTIVE;
  1220.  
  1221.     DLOG5("dp_settimos: t0 %d nt %d - %d %d %d\n", t0, nt,
  1222.       to[t0], to[t0+1], to[t0+2]);
  1223.     DLOG5("dp_settimos: timeouts %d %d %d %d %d\n", p->pii_timo[0] * DP_HZ,
  1224.       p->pii_timo[1] * DP_HZ, p->pii_timo[2] * DP_HZ,
  1225.       p->pii_timo[3] * DP_HZ, p->pii_timo[4] * DP_HZ);
  1226. }
  1227.  
  1228. static
  1229. dp_gettimos(p, to, t0, nt)
  1230. register PII *p;
  1231. register u_long *to;
  1232. register int t0, nt;
  1233. {
  1234.     register int t;
  1235.     for (t = 0 ; t < nt ; t++)
  1236.     to[t] = p->pii_timo[t0 + t] * DP_HZ;
  1237.     DLOG5("dp_gettimos: timeouts %d %d %d %d %d\n", p->pii_timo[0] * DP_HZ,
  1238.       p->pii_timo[1] * DP_HZ, p->pii_timo[2] * DP_HZ,
  1239.       p->pii_timo[3] * DP_HZ, p->pii_timo[4] * DP_HZ);
  1240. }
  1241.  
  1242. static
  1243. dp_state(p, dustate)
  1244. register PII *p;
  1245. register int dustate;
  1246. {
  1247.     if (p->pii_dustate == dustate)
  1248.     return;
  1249.     p->pii_dustate = dustate;
  1250.     p->pii_timer = p->pii_timo[p->pii_dustate];
  1251.     p->pii_ftimer = DP_NO_TIMEOUT;
  1252.     p->pii_ifnet.if_timer = (p->pii_timer > 0 || p->pii_ftimer > 0) ? DP_HZ : 0;
  1253. #ifdef    DEBUGS
  1254.     if (dp_if_debug || dp_ftimo_debug)
  1255.     log(LOG_INFO, "dp_state: %s %d %d (%d)\n", dus_str[dustate],
  1256.         p->pii_timer, p->pii_ftimer, p->pii_ifnet.if_timer);
  1257. #endif
  1258. }
  1259.  
  1260. static void
  1261. dp_event(p, timer)
  1262. register PII *p;
  1263. register int timer;
  1264. {
  1265.     register int timo;
  1266.     p->pii_timer = p->pii_timo[p->pii_dustate];
  1267.     switch (timer) {
  1268. #if    0
  1269.      case DP_ATIMEO:
  1270.     p->pii_ftimer = DP_NO_TIMEOUT;
  1271.     break;
  1272. #endif
  1273.      case DP_UTIMEO:
  1274.      case DP_CTIMEO:
  1275.     if ((timo = p->pii_timo[timer]) >= 0 && timo > p->pii_ftimer)
  1276.         p->pii_ftimer = timo;
  1277.     break;
  1278.     }
  1279.     p->pii_ifnet.if_timer = (p->pii_timer > 0 || p->pii_ftimer > 0) ? DP_HZ : 0;
  1280. #ifdef    DEBUGS
  1281.     if (dp_if_debug || dp_ftimo_debug)
  1282.     log(LOG_INFO, "dp_event: %s/%s %d %d (%d)\n",
  1283.         dus_str[p->pii_dustate], dus_str[timer],
  1284.         p->pii_timer, p->pii_ftimer, p->pii_ifnet.if_timer);
  1285. #endif
  1286. }
  1287.  
  1288. /*
  1289.  * dp_timer() provides for the following state transitions on timeout..
  1290.  *
  1291.  * State    Status         New State
  1292.  * FAILCALL    TIMEOUT        DISCON        (can try calling again)
  1293.  * ACTIVE    TIMEOUT        DISCON        (inactivity timeout)
  1294.  * WAITING    TIMEOUT        FAILCALL    (dialer is taking too long)
  1295.  */
  1296. static int
  1297. dp_timer(unit)
  1298. int unit;
  1299. {
  1300.     register PII *p = &dupii[unit];
  1301.     queue_t *q = p->pii_writeq;
  1302.     register int s;
  1303.  
  1304.  
  1305.     /* just being cautious by setting up the interrupt priority */
  1306.     s = splimp();
  1307.  
  1308.     /*
  1309.      * Count down the timers.
  1310.      */
  1311.     if (p->pii_timer > 0)
  1312.     p->pii_timer--;
  1313.     if (p->pii_ftimer > 0)
  1314.     p->pii_ftimer--;
  1315.  
  1316. #ifdef    DEBUGS
  1317.     if (dp_if_debug || dp_ftimo_debug)
  1318.     log(LOG_INFO, "dp_timer: before %s %d %d\n",
  1319.         dus_str[p->pii_dustate], p->pii_timer, p->pii_ftimer);
  1320. #endif
  1321.     /*
  1322.      * Ignore the fast timer expiration if we have active connections.
  1323.      */
  1324.     if (p->pii_ftimer == 0 && p->pii_active.da_nactive) {
  1325.     DLOGSTATE("dp_timer: fast timer ignored (%s)\n");
  1326. #ifdef    DEBUGS
  1327.     if (dp_if_debug || dp_ftimo_debug)
  1328.         log(LOG_INFO, "dp_timer: fast timer ignored (%s)\n",
  1329.             dus_str[p->pii_dustate]);
  1330. #endif
  1331.     p->pii_ftimer = DP_NO_TIMEOUT;
  1332.     }
  1333.  
  1334.     /*
  1335.      * If we are still counting down, get out of here..
  1336.      */
  1337.     if (p->pii_timer && p->pii_ftimer) {
  1338.     /* Reset the interface timer, and return */
  1339.     p->pii_ifnet.if_timer = DP_HZ;
  1340.     splx(s);
  1341.     return;
  1342.     }
  1343.  
  1344. #ifdef    DEBUGS
  1345.     if (dp_if_debug || dp_ftimo_debug)
  1346.     log(LOG_INFO, "dp_timer: %stimer expired, state = %s\n",
  1347.         p->pii_ftimer == 0 ? "fast " : "", dus_str[p->pii_dustate]);
  1348. #endif
  1349.     /*
  1350.      * One of the timers counted down to zero..
  1351.      */
  1352.     switch (p->pii_dustate) {
  1353.      case PII_DPS_DOWN:
  1354.      case PII_DPS_DISCON:
  1355.     /*
  1356.      * Do nothing....
  1357.      */
  1358.     break;
  1359.      case PII_DPS_WAITING:
  1360.     /*
  1361.      * Assume that the dialup program hung, so assume a failed call.
  1362.      */
  1363.     dp_state(p, PII_DPS_FAILCALL);
  1364.     dp_flush(p, q);
  1365.     DLOG("dp_timer: unit %d - we never had a line.\n", unit);
  1366.     break;
  1367.  
  1368.      case PII_DPS_ACTIVE:
  1369.     /*
  1370.      * Shut down the line for now by sending a signal to the PPP process.
  1371.      */
  1372.     dp_state(p, PII_DPS_DISCON);
  1373.     DLOG("dp_timer: sending SIGTERM to PPP process\n", unit);
  1374.     putctl1(RD(q), M_PCSIG, SIGTERM);
  1375.     break;
  1376.  
  1377.      case PII_DPS_FAILCALL:
  1378.     /*
  1379.      * Reenable the line for call attempts.
  1380.      */
  1381.     dp_state(p, PII_DPS_DISCON);
  1382.     break;
  1383.  
  1384.      default:
  1385.     DLOG("dp_timer: unknown state %d\n", p->pii_dustate);
  1386.     break;
  1387.     }
  1388.     splx(s);
  1389.     DLOGSTATE("dp_timer: after %s\n");
  1390. }
  1391.  
  1392. static void
  1393. dp_active_tinit(tab)
  1394. struct dp_ctab *tab;
  1395. {
  1396.     register struct dp_conv *conv = tab->dt_conv;
  1397.     register int i;
  1398.     for (i = MAX_ACTIVE - 1; i > 0; --i)
  1399.     conv[i].dc_next = &conv[i - 1];
  1400.     conv[0].dc_next = &conv[MAX_ACTIVE - 1];
  1401.     tab->dt_last = &conv[0];
  1402. }
  1403.  
  1404. static void
  1405. dp_active_init(act)
  1406. struct dp_active *act;
  1407. {
  1408.     bzero((char *)act, sizeof(*act));
  1409.     dp_active_tinit(&act->da_ttab);
  1410.     dp_active_tinit(&act->da_rtab);
  1411. }
  1412.  
  1413.  
  1414. static void dp_rstactive();
  1415.  
  1416. static void
  1417. dp_active(p, ip, len, xmit)
  1418. register PII *p;
  1419. register struct ip *ip;
  1420. int len;
  1421. int xmit;
  1422. {
  1423.     register struct dp_active *act;
  1424.     register struct dp_ctab *tab;
  1425.     register struct dp_conv *conv;
  1426.     register struct tcphdr *th;
  1427.     register u_int hlen;
  1428.  
  1429.     if (!(p->pii_flags & PII_FLAGS_ACTIVE)) {
  1430.     dp_event(p, DP_ATIMEO);
  1431.     return;
  1432.     }
  1433. #ifdef    DEBUGS
  1434.     act = &p->pii_active;
  1435. #endif
  1436.     /*
  1437.      * Don't bother with fragments.
  1438.      */
  1439.     if (len < sizeof(struct ip) || ip->ip_off & htons(0x3fff)) {
  1440.     DLOG_ACTIVE("len");
  1441.     return;
  1442.     }
  1443.  
  1444.     /*
  1445.      * Account for non-tcp traffic.
  1446.      */
  1447.     if (ip->ip_p != IPPROTO_TCP) {
  1448.     DLOG_ACTIVE("nontcp");
  1449.     dp_event(p, DP_UTIMEO);
  1450.     return;
  1451.     }
  1452.  
  1453.     /*
  1454.      * This shouldn't happen, but if it does,
  1455.      * Make sure we have enough of the TCP header to be interesting..
  1456.      */
  1457.     hlen = ip->ip_hl << 2;
  1458.     if (len < hlen + sizeof(struct tcphdr)) {
  1459.     DLOG_ACTIVE("len2");
  1460.     return;
  1461.     }
  1462.  
  1463.     /*
  1464.      * Look for the conversation in our table.
  1465.      * Check if it is the most recently used (it probably is).
  1466.      * If not, search the table in MRU order.
  1467.      */
  1468. #ifndef    DEBUGS
  1469.     act = &p->pii_active;
  1470. #endif
  1471.     th = (struct tcphdr *)&((char *)ip)[hlen];
  1472.     tab = xmit ? &act->da_ttab : &act->da_rtab;
  1473.     conv = tab->dt_last->dc_next;
  1474.     act->da_lookups++;
  1475.  
  1476.     if (ip->ip_src.s_addr != conv->dc_ip_src.s_addr ||
  1477.     ip->ip_dst.s_addr != conv->dc_ip_dst.s_addr ||
  1478.     *(int *)th != *((int *)&conv->dc_th_sport)) {
  1479.     /*
  1480.      * Not the most recently used conversation, look through the
  1481.      * circularly linked list.
  1482.      */
  1483.     register struct dp_conv *lconv,
  1484.                 *last = tab->dt_last;
  1485.  
  1486.     act->da_misses++;
  1487.     do {
  1488.         lconv = conv;
  1489.         conv = conv->dc_next;
  1490.         if (ip->ip_src.s_addr == conv->dc_ip_src.s_addr &&
  1491.         ip->ip_dst.s_addr == conv->dc_ip_dst.s_addr &&
  1492.         *(int *)th == *((int *)&conv->dc_th_sport)) {
  1493.         /*
  1494.          * This conversation is in the table somewhere.
  1495.          * Move it to the front of the list.
  1496.          */
  1497.         if (conv == last)
  1498.             tab->dt_last = lconv;
  1499.         else {
  1500.             lconv->dc_next = conv->dc_next;
  1501.             conv->dc_next = last->dc_next;
  1502.             last->dc_next = conv;
  1503.         }
  1504.         goto intable;
  1505.         }
  1506.     } while (conv != last);
  1507.  
  1508.     /*
  1509.      * If the LRU conversation is active, and we have at least one
  1510.      * inactive conversation, move the LRU inactive connection to the
  1511.      * LRU slot.
  1512.      *
  1513.      * It was considered best to scan the table again here to make
  1514.      * the first table scan quicker since it is executed more frequently.
  1515.      */
  1516.     if (conv->dc_flags & DC_ACTIVE) {
  1517.         register struct dp_conv *linact = (struct dp_conv *)0;
  1518.  
  1519.         lconv = tab->dt_last;
  1520.         conv = lconv->dc_next;
  1521.         if (!(conv->dc_flags & DC_ACTIVE))
  1522.         linact = lconv;
  1523.         do {
  1524.         lconv = conv;
  1525.         conv = conv->dc_next;
  1526.         if (!(conv->dc_flags & DC_ACTIVE))
  1527.             linact = lconv;
  1528.         } while (conv != last);
  1529.         if (linact) {
  1530.         conv = linact->dc_next;
  1531.         lconv = last;
  1532.  
  1533.         linact->dc_next = conv->dc_next;
  1534.         conv->dc_next = last->dc_next;
  1535.         last->dc_next = conv;
  1536.         }
  1537.     }
  1538. #if    1
  1539.     /*
  1540.      * With this #ifdef'ed out, the fast timeout will be effectively
  1541.      * disabled when more than MAX_ACTIVE (16) conversations are in effect.
  1542.      * With this included, MAX_ACTIVE fast connects and disconnects will
  1543.      * cause a fast timeout even if there are active conversations.
  1544.      */
  1545.     if (conv->dc_flags & DC_ACTIVE)
  1546.         act->da_nactive--;
  1547. #endif
  1548.     /*
  1549.      * This conversation is not in our table.
  1550.      * Create an entry for it in the least recently used slot.
  1551.      */
  1552.     tab->dt_last = lconv;
  1553.     conv->dc_ip_src.s_addr = ip->ip_src.s_addr;
  1554.     conv->dc_ip_dst.s_addr = ip->ip_dst.s_addr;
  1555.     *((int *)&conv->dc_th_sport) = *(int *)th;
  1556.     conv->dc_flags = DC_ACTIVE;
  1557.     act->da_nactive++;
  1558.     DLOG_ACTIVE("NEW");
  1559.     }
  1560.     
  1561. intable:
  1562.     if (conv->dc_flags & DC_ACTIVE) {
  1563.     if (th->th_flags & (TH_FIN|TH_RST)) {
  1564.         /*
  1565.          * Conversation shutting down
  1566.          */
  1567.         conv->dc_flags &= ~DC_ACTIVE;
  1568.         act->da_nactive--;
  1569.         DLOG_ACTIVE((th->th_flags & TH_FIN) ? "FIN" : "RST");
  1570.     }
  1571.     }
  1572.     else
  1573.     if (th->th_flags & TH_SYN) {
  1574.         /*
  1575.          * Conversation (re)starting
  1576.          */
  1577.         conv->dc_flags |= DC_ACTIVE;
  1578.         act->da_nactive++;
  1579.         DLOG_ACTIVE("SYN");
  1580.     }
  1581.     dp_event(p, act->da_nactive ? DP_ATIMEO : DP_CTIMEO);
  1582.     /*
  1583.      * On a reset, do special processing.
  1584.      */
  1585.     if (th->th_flags & TH_RST)
  1586.     dp_rstactive(p, ip, len, xmit);
  1587. }
  1588.  
  1589. /*
  1590.  * A reset affects both halves of a conversation.  Here, when a RST
  1591.  * happens on half of a conversation, we fake a FIN for the other half
  1592.  * since a TCP will never respond to a RST..
  1593.  */
  1594. static void
  1595. dp_rstactive(p, ip, len, xmit)
  1596. register PII *p;
  1597. register struct ip *ip;
  1598. int len;
  1599. int xmit;
  1600. {
  1601. #define    HDR_SLOP    44
  1602.     char revip[sizeof(struct ip)+sizeof(struct tcphdr)+HDR_SLOP];
  1603.     register struct ip *ip2 = (struct ip *)revip;
  1604.     register struct tcphdr *th, *th2;
  1605.     register u_int hlen = ip->ip_hl << 2;
  1606.  
  1607.     if (hlen + sizeof(struct tcphdr) > sizeof(revip))
  1608.     return;
  1609.     th  = (struct tcphdr *)&((char *)ip)[hlen];
  1610.     th2 = (struct tcphdr *)&((char *)ip2)[hlen];
  1611.     bcopy((char *)ip, (char *)ip2, hlen);
  1612.     th2->th_flags = (th->th_flags & ~TH_RST) | TH_FIN;
  1613.     ip2->ip_src = ip->ip_dst;
  1614.     ip2->ip_dst = ip->ip_src;
  1615.     th2->th_sport = th->th_dport;
  1616.     th2->th_dport = th->th_sport;
  1617.     dp_active(p, ip2, hlen + sizeof(struct tcphdr), !xmit);
  1618. }
  1619.  
  1620. /*
  1621.  * This code implements the streams device for communicating connect requests
  1622.  * to user-land.  This was formerly in a sepearate file (ppp_dial.c),
  1623.  * but in the expectation of future updates to allow loadable modules,
  1624.  * these two files were merged since one file calls a function in the
  1625.  * other file.  Loadable modules are apparently picky about that and there
  1626.  * is no way to get around the function call..
  1627.  */
  1628. #undef    DLOG
  1629. #ifdef    DEBUGS
  1630. #define    DLOG(s,a)    if(ppp_dial_debug) log(LOG_INFO, s, a)
  1631. int    ppp_dial_debug=0;
  1632. #else
  1633. #define    DLOG(s,a)    {}
  1634. #endif
  1635.  
  1636. static    int    ppp_dial_open(), ppp_dial_close(), ppp_dial_rsrv(),
  1637.         ppp_dial_wput();
  1638.  
  1639. static     struct    module_info    ppp_dial_minfo = {
  1640.     0xbae,"pppdial",0, INFPSZ, DP_HIWAT, DP_LOWAT
  1641. };
  1642.  
  1643. static    struct    qinit    ppp_dial_rinit = {
  1644.     NULL, ppp_dial_rsrv, ppp_dial_open, ppp_dial_close, NULL,
  1645.     &ppp_dial_minfo, NULL
  1646. };
  1647. static    struct    qinit    ppp_dial_winit = {
  1648.     ppp_dial_wput, NULL, NULL, NULL, NULL,
  1649.     &ppp_dial_minfo, NULL
  1650. };
  1651. struct    streamtab    ppp_dialinfo = {
  1652.     &ppp_dial_rinit, &ppp_dial_winit, NULL, NULL, NULL
  1653. };
  1654.  
  1655. queue_t *req_q;
  1656.  
  1657. static int
  1658. ppp_dial_open(q, dev, flag, sflag)
  1659. queue_t    *q;
  1660. dev_t    dev;
  1661. int    flag,
  1662.     sflag;
  1663.  
  1664. {
  1665.     if (!suser()) {
  1666.     u.u_error = EPERM;
  1667.     return(OPENFAIL);
  1668.     }
  1669.     /*
  1670.      * Insure this is a normal driver open..
  1671.      */
  1672.     if (sflag)
  1673.     return (OPENFAIL);
  1674.  
  1675.     /*
  1676.      * Insure exclusive access.
  1677.      */
  1678.     if (q->q_ptr) {
  1679.     u.u_error = EBUSY;
  1680.     return(OPENFAIL);
  1681.     }
  1682.  
  1683.     q->q_ptr = "ppp daemon running";
  1684.     req_q = q;
  1685.     DLOG("ppp_dial%d: open\n", minor(dev));
  1686.     return dev;
  1687. }
  1688.  
  1689. static int
  1690. ppp_dial_close(q)
  1691. queue_t    *q;            /* queue info */
  1692. {
  1693.     req_q = (queue_t *)0;
  1694.     q->q_ptr = (char *)0;
  1695.     DLOG("ppp_dial: close\n", 0);
  1696.     return 0;
  1697. }
  1698.  
  1699.  
  1700. static int
  1701. ppp_dial_wput(q, mp)
  1702. queue_t  *q;
  1703. register mblk_t *mp;
  1704. {
  1705.     switch (mp->b_datap->db_type) {
  1706.      case  M_FLUSH:
  1707.     if (*mp->b_rptr & FLUSHW)
  1708.         flushq(q, FLUSHDATA);
  1709.     if (*mp->b_rptr & FLUSHR) {
  1710.         flushq(RD(q), FLUSHDATA);
  1711.         *mp->b_rptr &= ~FLUSHW;
  1712.         qreply(q, mp);
  1713.     }
  1714.     else 
  1715.         freemsg(mp);
  1716.     break;
  1717.      case M_DATA:
  1718.      case M_IOCTL:
  1719.      default:
  1720.     /*
  1721.      * For now, do nothing with stuff written to the stream.
  1722.      * Later on, support returning status of dial
  1723.      * operations.
  1724.      */
  1725.     freemsg(mp);
  1726.     break;
  1727.     }
  1728.  
  1729. }
  1730.  
  1731. static int
  1732. ppp_dial_rsrv(q)
  1733. queue_t *q;
  1734. {
  1735.     register mblk_t *mp;
  1736.  
  1737.     while ((mp = getq(q)) != NULL) {
  1738.     switch (mp->b_datap->db_type) {
  1739.      case M_FLUSH:
  1740.         if(*mp->b_rptr & FLUSHR)
  1741.         flushq(q, FLUSHDATA);
  1742.         DLOG("ppp_dial_rsrv: M_FLUSH\n", 0);
  1743.         putnext(q, mp);        /* send it along too */
  1744.         break;
  1745.      case M_DATA:
  1746.         if (!canput(q->q_next)) {
  1747. #define    DISCARD_OLDEST
  1748. #ifdef    DISCARD_OLDEST
  1749.         register mblk_t *omp;
  1750.         /*
  1751.          * Throw away something..
  1752.          */
  1753.         omp = getq(q->q_next);
  1754.         freemsg(omp);
  1755. #endif
  1756. #ifdef    DISCARD_NEWEST
  1757.         freemsg(mp);
  1758.         break;
  1759. #endif
  1760.         }
  1761.         /*
  1762.          * Just send this along..
  1763.          */
  1764.      default:
  1765.         DLOG("ppp_dial_rsrv: M_DATA\n", 0);
  1766.         putnext(q, mp);
  1767.     }
  1768.     }
  1769. }
  1770.  
  1771. static
  1772. duipreq(m0, dst, ifp, checkit)
  1773. struct mbuf *m0;
  1774. struct sockaddr *dst;
  1775. struct ifnet *ifp;
  1776. int checkit;
  1777. {
  1778.     register mblk_t *mp;
  1779.     struct dp_req *req;
  1780.     struct mbuf *m;
  1781.     int s;
  1782.     int i;
  1783.     int len;
  1784.     queue_t *q;
  1785.  
  1786.     /*
  1787.      * If no program is accepting requests, return immediate failure.
  1788.      */
  1789.     if (!(q = req_q))
  1790.     return -1;
  1791.     /*
  1792.      * Check how much header we have and arrange to send at least
  1793.      * DR_MINHDRLEN but not more than DR_MAXHDRLEN to the program
  1794.      * handling calls (dpd).
  1795.      */
  1796.     for (len = 0, m = m0 ; m && len <= DR_MAXHDRLEN ; m = m->m_next)
  1797.     len += m->m_len;
  1798.     if (len < DR_MINHDRLEN)
  1799.     return -1;
  1800.     if (len > DR_MAXHDRLEN)
  1801.     len = DR_MAXHDRLEN;
  1802.  
  1803.     /*
  1804.      * Allocate the appropriate stream data structure for this request.
  1805.      */
  1806.     s = splstr();
  1807.     mp = allocb(sizeof(struct dp_reqinfo) + len, BPRI_MED);
  1808.     if (!mp) {
  1809.     splx(s);
  1810.     return -1;
  1811.     }
  1812.  
  1813.     /*
  1814.      * Fill in the request info.
  1815.      */
  1816.     req = (struct dp_req *)mp->b_wptr;
  1817.     mp->b_wptr += sizeof (struct dp_reqinfo);
  1818.     for (i = 0 ; i < sizeof(req->dr_ifname) ; i++)
  1819.     if (!(req->dr_ifname[i] = ifp->if_name[i]))
  1820.         break;
  1821.     for ( i++ ; i < sizeof(req->dr_ifname) ; i++)
  1822.     req->dr_ifname[i] = '\0';
  1823.     req->dr_ifunit = ifp->if_unit;
  1824.     req->dr_flag = checkit ? DP_REQ_CHECKIT : 0;
  1825.     bcopy(dst, &req->dr_sin, sizeof(struct sockaddr_in));
  1826.     req->dr_hdrlen = len;
  1827.     /*
  1828.      * Copy the header data, in chunks if necessary.
  1829.      */
  1830.     for (m = m0 ; len > 0 && m ; m = m->m_next) {
  1831.     i = MIN(len, m->m_len);
  1832.     bcopy(mtod(m, char *), mp->b_wptr, i);
  1833.     len -= i;
  1834.     mp->b_wptr += i;
  1835.     }
  1836.     /*
  1837.      * Send this stream stuff to the program.
  1838.      */
  1839.     putq(q, mp);
  1840.     splx(s);
  1841.     DLOG("duipreq\n", 0);
  1842.     return 0;
  1843. }
  1844.  
  1845. /*
  1846.  * slcompress.c is included here with small changes, to make loadable
  1847.  * module implementation easier... peter@micromuse.co.uk
  1848.  */
  1849.  
  1850. /*
  1851.  * Routines to compress and uncompess tcp packets (for transmission
  1852.  * over low speed serial lines.
  1853.  *
  1854.  * Copyright (c) 1989 Regents of the University of California.
  1855.  * All rights reserved.
  1856.  *
  1857.  * Redistribution and use in source and binary forms are permitted
  1858.  * provided that the above copyright notice and this paragraph are
  1859.  * duplicated in all such forms and that any documentation,
  1860.  * advertising materials, and other materials related to such
  1861.  * distribution and use acknowledge that the software was developed
  1862.  * by the University of California, Berkeley.  The name of the
  1863.  * University may not be used to endorse or promote products derived
  1864.  * from this software without specific prior written permission.
  1865.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1866.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1867.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1868.  *
  1869.  *    Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
  1870.  *    - Initial distribution.
  1871.  */
  1872.  
  1873. #ifndef SL_NO_STATS
  1874. #define SLINCR(counter) ++comp->counter;
  1875. #else
  1876. #define SLINCR(counter)
  1877. #endif
  1878.  
  1879. #define SLBCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
  1880. #define SLBCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
  1881. #ifndef KERNEL
  1882. #define ovbcopy bcopy
  1883. #endif
  1884.  
  1885.  
  1886. static void
  1887. sl_compress_init(comp)
  1888.     struct slcompress *comp;
  1889. {
  1890.     register u_int i;
  1891.     register struct cstate *tstate = comp->tstate;
  1892.  
  1893.     bzero((char *)comp, sizeof(*comp));
  1894.     for (i = MAX_STATES - 1; i > 0; --i) {
  1895.         tstate[i].cs_id = i;
  1896.         tstate[i].cs_next = &tstate[i - 1];
  1897.     }
  1898.     tstate[0].cs_next = &tstate[MAX_STATES - 1];
  1899.     tstate[0].cs_id = 0;
  1900.     comp->last_cs = &tstate[0];
  1901.     comp->last_recv = 255;
  1902.     comp->last_xmit = 255;
  1903.     comp->flags = SLF_TOSS;
  1904. }
  1905.  
  1906.  
  1907. /* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
  1908.  * checks for zero (since zero has to be encoded in the long, 3 byte
  1909.  * form).
  1910.  */
  1911. #define ENCODE(n) { \
  1912.     if ((u_short)(n) >= 256) { \
  1913.         *cp++ = 0; \
  1914.         cp[1] = (n); \
  1915.         cp[0] = (n) >> 8; \
  1916.         cp += 2; \
  1917.     } else { \
  1918.         *cp++ = (n); \
  1919.     } \
  1920. }
  1921. #define ENCODEZ(n) { \
  1922.     if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
  1923.         *cp++ = 0; \
  1924.         cp[1] = (n); \
  1925.         cp[0] = (n) >> 8; \
  1926.         cp += 2; \
  1927.     } else { \
  1928.         *cp++ = (n); \
  1929.     } \
  1930. }
  1931.  
  1932. #define DECODEL(f) { \
  1933.     if (*cp == 0) {\
  1934.         (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
  1935.         cp += 3; \
  1936.     } else { \
  1937.         (f) = htonl(ntohl(f) + (u_long)*cp++); \
  1938.     } \
  1939. }
  1940.  
  1941. #define DECODES(f) { \
  1942.     if (*cp == 0) {\
  1943.         (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
  1944.         cp += 3; \
  1945.     } else { \
  1946.         (f) = htons(ntohs(f) + (u_long)*cp++); \
  1947.     } \
  1948. }
  1949.  
  1950. #define DECODEU(f) { \
  1951.     if (*cp == 0) {\
  1952.         (f) = htons((cp[1] << 8) | cp[2]); \
  1953.         cp += 3; \
  1954.     } else { \
  1955.         (f) = htons((u_long)*cp++); \
  1956.     } \
  1957. }
  1958.  
  1959.  
  1960. static u_char
  1961. sl_compress_tcp(m, ip, comp, compress_cid)
  1962.     struct mbuf *m;
  1963.     register struct ip *ip;
  1964.     struct slcompress *comp;
  1965.     int compress_cid;
  1966. {
  1967.     register struct cstate *cs = comp->last_cs->cs_next;
  1968.     register u_int hlen = ip->ip_hl;
  1969.     register struct tcphdr *oth;
  1970.     register struct tcphdr *th;
  1971.     register u_int deltaS, deltaA;
  1972.     register u_int changes = 0;
  1973.     u_char new_seq[16];
  1974.     register u_char *cp = new_seq;
  1975.  
  1976.     /*
  1977.      * Bail if this is an IP fragment or if the TCP packet isn't
  1978.      * `compressible' (i.e., ACK isn't set or some other control bit is
  1979.      * set).  (We assume that the caller has already made sure the
  1980.      * packet is IP proto TCP).
  1981.      */
  1982.     if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
  1983.         return (TYPE_IP);
  1984.  
  1985.     th = (struct tcphdr *)&((int *)ip)[hlen];
  1986.     if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
  1987.         return (TYPE_IP);
  1988.     /*
  1989.      * Packet is compressible -- we're going to send either a
  1990.      * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
  1991.      * to locate (or create) the connection state.  Special case the
  1992.      * most recently used connection since it's most likely to be used
  1993.      * again & we don't have to do any reordering if it's used.
  1994.      */
  1995.     SLINCR(sls_packets)
  1996.     if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
  1997.         ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
  1998.         *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
  1999.         /*
  2000.          * Wasn't the first -- search for it.
  2001.          *
  2002.          * States are kept in a circularly linked list with
  2003.          * last_cs pointing to the end of the list.  The
  2004.          * list is kept in lru order by moving a state to the
  2005.          * head of the list whenever it is referenced.  Since
  2006.          * the list is short and, empirically, the connection
  2007.          * we want is almost always near the front, we locate
  2008.          * states via linear search.  If we don't find a state
  2009.          * for the datagram, the oldest state is (re-)used.
  2010.          */
  2011.         register struct cstate *lcs;
  2012.         register struct cstate *lastcs = comp->last_cs;
  2013.  
  2014.         do {
  2015.             lcs = cs; cs = cs->cs_next;
  2016.             SLINCR(sls_searches)
  2017.             if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
  2018.                 && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
  2019.                 && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl])
  2020.                 goto found;
  2021.         } while (cs != lastcs);
  2022.  
  2023.         /*
  2024.          * Didn't find it -- re-use oldest cstate.  Send an
  2025.          * uncompressed packet that tells the other side what
  2026.          * connection number we're using for this conversation.
  2027.          * Note that since the state list is circular, the oldest
  2028.          * state points to the newest and we only need to set
  2029.          * last_cs to update the lru linkage.
  2030.          */
  2031.         SLINCR(sls_misses)
  2032.         comp->last_cs = lcs;
  2033.         hlen += th->th_off;
  2034.         hlen <<= 2;
  2035.         goto uncompressed;
  2036.  
  2037.     found:
  2038.         /*
  2039.          * Found it -- move to the front on the connection list.
  2040.          */
  2041.         if (cs == lastcs)
  2042.             comp->last_cs = lcs;
  2043.         else {
  2044.             lcs->cs_next = cs->cs_next;
  2045.             cs->cs_next = lastcs->cs_next;
  2046.             lastcs->cs_next = cs;
  2047.         }
  2048.     }
  2049.  
  2050.     /*
  2051.      * Make sure that only what we expect to change changed. The first
  2052.      * line of the `if' checks the IP protocol version, header length &
  2053.      * type of service.  The 2nd line checks the "Don't fragment" bit.
  2054.      * The 3rd line checks the time-to-live and protocol (the protocol
  2055.      * check is unnecessary but costless).  The 4th line checks the TCP
  2056.      * header length.  The 5th line checks IP options, if any.  The 6th
  2057.      * line checks TCP options, if any.  If any of these things are
  2058.      * different between the previous & current datagram, we send the
  2059.      * current datagram `uncompressed'.
  2060.      */
  2061.     oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
  2062.     deltaS = hlen;
  2063.     hlen += th->th_off;
  2064.     hlen <<= 2;
  2065.  
  2066.     if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
  2067.         ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
  2068.         ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
  2069.         th->th_off != oth->th_off ||
  2070.         (deltaS > 5 &&
  2071.          SLBCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
  2072.         (th->th_off > 5 &&
  2073.          SLBCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
  2074.         goto uncompressed;
  2075.  
  2076.     /*
  2077.      * Figure out which of the changing fields changed.  The
  2078.      * receiver expects changes in the order: urgent, window,
  2079.      * ack, seq (the order minimizes the number of temporaries
  2080.      * needed in this section of code).
  2081.      */
  2082.     if (th->th_flags & TH_URG) {
  2083.         deltaS = ntohs(th->th_urp);
  2084.         ENCODEZ(deltaS);
  2085.         changes |= NEW_U;
  2086.     } else if (th->th_urp != oth->th_urp)
  2087.         /* argh! URG not set but urp changed -- a sensible
  2088.          * implementation should never do this but RFC793
  2089.          * doesn't prohibit the change so we have to deal
  2090.          * with it. */
  2091.          goto uncompressed;
  2092.  
  2093.     if (deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) {
  2094.         ENCODE(deltaS);
  2095.         changes |= NEW_W;
  2096.     }
  2097.  
  2098.     if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) {
  2099.         if (deltaA > 0xffff)
  2100.             goto uncompressed;
  2101.         ENCODE(deltaA);
  2102.         changes |= NEW_A;
  2103.     }
  2104.  
  2105.     if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) {
  2106.         if (deltaS > 0xffff)
  2107.             goto uncompressed;
  2108.         ENCODE(deltaS);
  2109.         changes |= NEW_S;
  2110.     }
  2111.  
  2112.     switch(changes) {
  2113.  
  2114.     case 0:
  2115.         /*
  2116.          * Nothing changed. If this packet contains data and the
  2117.          * last one didn't, this is probably a data packet following
  2118.          * an ack (normal on an interactive connection) and we send
  2119.          * it compressed.  Otherwise it's probably a retransmit,
  2120.          * retransmitted ack or window probe.  Send it uncompressed
  2121.          * in case the other side missed the compressed version.
  2122.          */
  2123.         if (ip->ip_len != cs->cs_ip.ip_len &&
  2124.             ntohs(cs->cs_ip.ip_len) == hlen)
  2125.             break;
  2126.  
  2127.         /* (fall through) */
  2128.  
  2129.     case SPECIAL_I:
  2130.     case SPECIAL_D:
  2131.         /*
  2132.          * actual changes match one of our special case encodings --
  2133.          * send packet uncompressed.
  2134.          */
  2135.         goto uncompressed;
  2136.  
  2137.     case NEW_S|NEW_A:
  2138.         if (deltaS == deltaA &&
  2139.             deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
  2140.             /* special case for echoed terminal traffic */
  2141.             changes = SPECIAL_I;
  2142.             cp = new_seq;
  2143.         }
  2144.         break;
  2145.  
  2146.     case NEW_S:
  2147.         if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
  2148.             /* special case for data xfer */
  2149.             changes = SPECIAL_D;
  2150.             cp = new_seq;
  2151.         }
  2152.         break;
  2153.     }
  2154.  
  2155.     deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
  2156.     if (deltaS != 1) {
  2157.         ENCODEZ(deltaS);
  2158.         changes |= NEW_I;
  2159.     }
  2160.     if (th->th_flags & TH_PUSH)
  2161.         changes |= TCP_PUSH_BIT;
  2162.     /*
  2163.      * Grab the cksum before we overwrite it below.  Then update our
  2164.      * state with this packet's header.
  2165.      */
  2166.     deltaA = ntohs(th->th_sum);
  2167.     SLBCOPY(ip, &cs->cs_ip, hlen);
  2168.  
  2169.     /*
  2170.      * We want to use the original packet as our compressed packet.
  2171.      * (cp - new_seq) is the number of bytes we need for compressed
  2172.      * sequence numbers.  In addition we need one byte for the change
  2173.      * mask, one for the connection id and two for the tcp checksum.
  2174.      * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
  2175.      * many bytes of the original packet to toss so subtract the two to
  2176.      * get the new packet size.
  2177.      */
  2178.     deltaS = cp - new_seq;
  2179.     cp = (u_char *)ip;
  2180.     if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
  2181.         comp->last_xmit = cs->cs_id;
  2182.         hlen -= deltaS + 4;
  2183.         cp += hlen;
  2184.         *cp++ = changes | NEW_C;
  2185.         *cp++ = cs->cs_id;
  2186.     } else {
  2187.         hlen -= deltaS + 3;
  2188.         cp += hlen;
  2189.         *cp++ = changes;
  2190.     }
  2191.     m->m_len -= hlen;
  2192.     m->m_off += hlen;
  2193.     *cp++ = deltaA >> 8;
  2194.     *cp++ = deltaA;
  2195.     SLBCOPY(new_seq, cp, deltaS);
  2196.     SLINCR(sls_compressed)
  2197.     return (TYPE_COMPRESSED_TCP);
  2198.  
  2199.     /*
  2200.      * Update connection state cs & send uncompressed packet ('uncompressed'
  2201.      * means a regular ip/tcp packet but with the 'conversation id' we hope
  2202.      * to use on future compressed packets in the protocol field).
  2203.      */
  2204. uncompressed:
  2205.     SLBCOPY(ip, &cs->cs_ip, hlen);
  2206.     ip->ip_p = cs->cs_id;
  2207.     comp->last_xmit = cs->cs_id;
  2208.     return (TYPE_UNCOMPRESSED_TCP);
  2209. }
  2210.  
  2211.  
  2212. static int
  2213. sl_uncompress_tcp(bufp, len, type, comp)
  2214.     u_char **bufp;
  2215.     int len;
  2216.     u_int type;
  2217.     struct slcompress *comp;
  2218. {
  2219.     register u_char *cp;
  2220.     register u_int hlen, changes;
  2221.     register struct tcphdr *th;
  2222.     register struct cstate *cs;
  2223.     register struct ip *ip;
  2224.  
  2225.     switch (type) {
  2226.  
  2227.     case TYPE_UNCOMPRESSED_TCP:
  2228.         ip = (struct ip *) *bufp;
  2229.         if (ip->ip_p >= MAX_STATES)
  2230.             goto bad;
  2231.         cs = &comp->rstate[comp->last_recv = ip->ip_p];
  2232.         comp->flags &=~ SLF_TOSS;
  2233.         ip->ip_p = IPPROTO_TCP;
  2234.         hlen = ip->ip_hl;
  2235.         hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off;
  2236.         hlen <<= 2;
  2237.         SLBCOPY(ip, &cs->cs_ip, hlen);
  2238.         cs->cs_ip.ip_sum = 0;
  2239.         cs->cs_hlen = hlen;
  2240.         SLINCR(sls_uncompressedin)
  2241.         return (len);
  2242.  
  2243.     default:
  2244.         goto bad;
  2245.  
  2246.     case TYPE_COMPRESSED_TCP:
  2247.         break;
  2248.     }
  2249.     /* We've got a compressed packet. */
  2250.     SLINCR(sls_compressedin)
  2251.     cp = *bufp;
  2252.     changes = *cp++;
  2253.     if (changes & NEW_C) {
  2254.         /* Make sure the state index is in range, then grab the state.
  2255.          * If we have a good state index, clear the 'discard' flag. */
  2256.         if (*cp >= MAX_STATES)
  2257.             goto bad;
  2258.  
  2259.         comp->flags &=~ SLF_TOSS;
  2260.         comp->last_recv = *cp++;
  2261.     } else {
  2262.         /* this packet has an implicit state index.  If we've
  2263.          * had a line error since the last time we got an
  2264.          * explicit state index, we have to toss the packet. */
  2265.         if (comp->flags & SLF_TOSS) {
  2266.             SLINCR(sls_tossed)
  2267.             return (0);
  2268.         }
  2269.     }
  2270.     cs = &comp->rstate[comp->last_recv];
  2271.     hlen = cs->cs_ip.ip_hl << 2;
  2272.     th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
  2273.     th->th_sum = htons((*cp << 8) | cp[1]);
  2274.     cp += 2;
  2275.     if (changes & TCP_PUSH_BIT)
  2276.         th->th_flags |= TH_PUSH;
  2277.     else
  2278.         th->th_flags &=~ TH_PUSH;
  2279.  
  2280.     switch (changes & SPECIALS_MASK) {
  2281.     case SPECIAL_I:
  2282.         {
  2283.         register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
  2284.         th->th_ack = htonl(ntohl(th->th_ack) + i);
  2285.         th->th_seq = htonl(ntohl(th->th_seq) + i);
  2286.         }
  2287.         break;
  2288.  
  2289.     case SPECIAL_D:
  2290.         th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
  2291.                    - cs->cs_hlen);
  2292.         break;
  2293.  
  2294.     default:
  2295.         if (changes & NEW_U) {
  2296.             th->th_flags |= TH_URG;
  2297.             DECODEU(th->th_urp)
  2298.         } else
  2299.             th->th_flags &=~ TH_URG;
  2300.         if (changes & NEW_W)
  2301.             DECODES(th->th_win)
  2302.         if (changes & NEW_A)
  2303.             DECODEL(th->th_ack)
  2304.         if (changes & NEW_S)
  2305.             DECODEL(th->th_seq)
  2306.         break;
  2307.     }
  2308.     if (changes & NEW_I) {
  2309.         DECODES(cs->cs_ip.ip_id)
  2310.     } else
  2311.         cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
  2312.  
  2313.     /*
  2314.      * At this point, cp points to the first byte of data in the
  2315.      * packet.  If we're not aligned on a 4-byte boundary, copy the
  2316.      * data down so the ip & tcp headers will be aligned.  Then back up
  2317.      * cp by the tcp/ip header length to make room for the reconstructed
  2318.      * header (we assume the packet we were handed has enough space to
  2319.      * prepend 128 bytes of header).  Adjust the length to account for
  2320.      * the new header & fill in the IP total length.
  2321.      */
  2322.     len -= (cp - *bufp);
  2323.     if (len < 0)
  2324.         /* we must have dropped some characters (crc should detect
  2325.          * this but the old slip framing won't) */
  2326.         goto bad;
  2327.  
  2328.     if ((int)cp & 3) {
  2329.         if (len > 0)
  2330.             (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len);
  2331.         cp = (u_char *)((int)cp &~ 3);
  2332.     }
  2333.     cp -= cs->cs_hlen;
  2334.     len += cs->cs_hlen;
  2335.     cs->cs_ip.ip_len = htons(len);
  2336.     SLBCOPY(&cs->cs_ip, cp, cs->cs_hlen);
  2337.     *bufp = cp;
  2338.  
  2339.     /* recompute the ip header checksum */
  2340.     {
  2341.         register u_short *bp = (u_short *)cp;
  2342.         for (changes = 0; hlen > 0; hlen -= 2)
  2343.             changes += *bp++;
  2344.         changes = (changes & 0xffff) + (changes >> 16);
  2345.         changes = (changes & 0xffff) + (changes >> 16);
  2346.         ((struct ip *)cp)->ip_sum = ~ changes;
  2347.     }
  2348.     return (len);
  2349. bad:
  2350.     comp->flags |= SLF_TOSS;
  2351.     SLINCR(sls_errorin)
  2352.     return (0);
  2353. }
  2354.  
  2355. #ifdef    LOADABLE
  2356.  
  2357. #define    LOG_INUSE    1
  2358.  
  2359. struct cdevsw ppp_cdevsw = {
  2360.      0, 0, 0, 0, 0, 0, 0, 0, &ppp_dialinfo, 0
  2361. };
  2362.  
  2363. static struct log { 
  2364.     char flags;
  2365.     char nr;
  2366. } dp_if_log[NDP], ppp_dial_log[NDP];
  2367.  
  2368. static struct vdldrv ppp_dial_vd = {
  2369.     VDMAGIC_PSEUDO,
  2370.     "Dialup PPP Interface",
  2371. #if    defined(sun4c) || defined(sun4m)
  2372.     NULL,
  2373. #else
  2374.     (struct mb_ctlr *)NULL,
  2375.     (struct mb_driver *)NULL,
  2376.     (struct mb_device *)NULL,
  2377.     NULL,
  2378.     NULL,
  2379. #endif
  2380.     NULL,
  2381.     &ppp_cdevsw,
  2382.     0,
  2383.     0,
  2384. };
  2385.  
  2386. static struct fmodsw *fmod_dp_if;
  2387. static struct fmodsw *fmod_ppp_dial;
  2388.  
  2389. dpmod_init(fc,vdp,vdi,vds)
  2390. unsigned int fc;
  2391. struct vddrv *vdp;
  2392. addr_t vdi;
  2393. struct vdstat *vds;
  2394. {
  2395.     dp_if_init(fc, vdp, vdi, vds);
  2396.     ppp_dial_init(fc, vdp, vdi, vds);
  2397.     return 0;
  2398. }
  2399.  
  2400.  
  2401. static
  2402. dp_if_init(fc,vdp,vdi,vds)
  2403. unsigned int fc;
  2404. struct vddrv *vdp;
  2405. addr_t vdi;
  2406. struct vdstat *vds;
  2407. {
  2408.     register int i;
  2409.     register struct dp_if_info *p;
  2410.     switch(fc) {
  2411.         case VDLOAD:
  2412.         {
  2413.             register int i;
  2414.             for(i = 0; i < fmodcnt; i++) {
  2415.                 if(fmodsw[i].f_str == NULL)
  2416.                     break;
  2417.             }
  2418.             if(i == fmodcnt)
  2419.                 return(ENODEV);
  2420.             fmod_dp_if = &fmodsw[i];
  2421.             fmod_dp_if->f_str = &dp_ifinfo;
  2422.             bcopy(dp_minfo.mi_idname, fmod_dp_if->f_name, FMNAMESZ);
  2423.             for (i = 0; i < NDP; i++)
  2424.                 dp_attach(i);
  2425.         return 0;
  2426.         }
  2427.  
  2428. /* Paul Fox says you only need this line if you have a real device
  2429.  * to add to the cdevsw/bdevsw structures, so this should be safe :-)
  2430.  * (It seems to work) It goes above by the way.
  2431.  *
  2432.  *        vdp->vdd_vdtab = (struct vdlinkage *) &dp_if_vd;
  2433.  */
  2434.         case VDUNLOAD:
  2435.         {
  2436.             int dev;
  2437.             for (dev = 0; dev < NDP; dev++) 
  2438.                 if (dupii[dev].pii_flags & PII_FLAGS_INUSE)
  2439.                     return (EBUSY);
  2440.             }
  2441.             for (i = 0, p = dupii; i < NDP; i++, p++) {
  2442.             /***********************************************/
  2443.             /*   Loadable  driver  needs  to  detach from  */
  2444.             /*   ifnet   structure   otherwise  we  panic  */
  2445.             /*   system  as  soon  as  if_slowtimo() goes  */
  2446.             /*   off  because  it  has a list pointing to  */
  2447.             /*   the   memory   which   will   have  been  */
  2448.             /*   deallocated.                   */
  2449.             /***********************************************/
  2450.             if (p->pii_flags & PII_FLAGS_ATTACHED) {
  2451.                 if (dp_detach(p) == 0)
  2452.                     return EBUSY;
  2453.                 p->pii_flags &= ~PII_FLAGS_ATTACHED;
  2454.                 }
  2455.             fmod_dp_if->f_name[0] = '\0';
  2456.             fmod_dp_if->f_str = NULL;
  2457.         }
  2458.             return 0;
  2459.         case VDSTAT:
  2460.             return 0;
  2461.         default:
  2462.             return EIO;
  2463.     }
  2464. }
  2465.  
  2466. static
  2467. ppp_dial_init(fc,vdp,vdi,vds)
  2468. unsigned int fc;
  2469. struct vddrv *vdp;
  2470. addr_t vdi;
  2471. struct vdstat *vds;
  2472. {
  2473.     register int i;
  2474.     switch(fc) {
  2475.         case VDLOAD:
  2476.         {
  2477.             for(i=0; i < fmodcnt; i++) {
  2478.                 if(fmodsw[i].f_str == NULL)
  2479.                     break;
  2480.             }
  2481.             if(i == fmodcnt)
  2482.                 return(ENODEV);
  2483.             fmod_ppp_dial = &fmodsw[i];
  2484.             fmod_ppp_dial->f_str = &ppp_dialinfo;
  2485.             bcopy(ppp_dial_minfo.mi_idname, fmod_ppp_dial->f_name, FMNAMESZ);
  2486.             vdp->vdd_vdtab = (struct vdlinkage *) &ppp_dial_vd;
  2487.             return 0;
  2488.         }
  2489.         case VDUNLOAD:
  2490.         {
  2491.             for (i = 0; i < NDP; i++) 
  2492.                 if (ppp_dial_log[i].flags & LOG_INUSE)
  2493.                     return (EIO);
  2494.             fmod_ppp_dial->f_name[0] = '\0';
  2495.             fmod_ppp_dial->f_str = NULL;
  2496.             return 0;
  2497.         }
  2498.         case VDSTAT:
  2499.             return 0;
  2500.         default:
  2501.             return EIO;
  2502.     }
  2503. }
  2504.  
  2505. /**********************************************************************/
  2506. /*   Routine  to  detach a PPP device from the ifnet structure (list  */
  2507. /*   of  interfaces).  Kernel doesn't provide any routines for doing  */
  2508. /*   this  for  loadable  device  drivers and we must avoid panicing  */
  2509. /*   the system.                              */
  2510. /**********************************************************************/
  2511. static int
  2512. dp_detach(pp)
  2513. register struct dp_if_info *pp;
  2514. {    struct ifnet **p = &ifnet;
  2515.     struct ifnet *ifp = &pp->pii_ifnet;
  2516.  
  2517.     while (*p) {
  2518.         if (*p == ifp) {
  2519.             *p = ifp->if_next;
  2520.             return 1;
  2521.             }
  2522.         p = &((*p)->if_next);
  2523.         }
  2524.     return 0;
  2525. }
  2526.  
  2527. #endif /* LOADABLE */
  2528. #endif NDP > 0
  2529.